/* 
 * Copyright (c)	Insighten Intelligent Equipment co.,LTD
 * 
 *  Use of this software is controlled by the terms and conditions found
 *  in the license agreement under which this software has been supplied.
 * 
 */
/** 
 * @file tcp_client.c
 * @brief library for client
 * @author taco [tacoee@gmail.com]
 * @version 0.1
 * @date 2010-09-03
 */
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>

#include "tcp_client.h"
#include "sock_util.h"

TcpClient *tcp_client_new(void)
{
	TcpClient *thiz = NULL;

	thiz = calloc(sizeof(TcpClient), 1);

	return thiz;
}

Ret tcp_client_destroy(TcpClient *thiz)
{
	if (thiz != NULL) {
		if (thiz->fd != -1) {
			close(thiz->fd);
		}
		thiz->buf = NULL;
		free(thiz);
		return RET_OK;
	}

	return RET_NO_TARGET;
}

Ret tcp_client_init(TcpClient *thiz, int port, char *hsn, SocketAttr *attr, RwBuf *buf)
{
	if (thiz != NULL) {
		thiz->fd = -1;
		thiz->port = port;
		thiz->host_name = hsn;
		thiz->svr_name = gethostbyname(hsn);
		if (thiz->svr_name == NULL) {
			return RET_FAIL;
		}
		memset(&thiz->addr, 0, sizeof(thiz->addr));
		thiz->addr.sin_family = AF_INET;
		thiz->addr.sin_addr.s_addr = htonl(INADDR_ANY);
		thiz->addr.sin_addr.s_addr = ((struct in_addr *)(thiz->svr_name->h_addr))->s_addr;
		thiz->addr.sin_port = htons(port);
		thiz->addr_len = sizeof(thiz->addr);
		thiz->attr = attr;
		thiz->buf = buf;

		return RET_OK;
	}
	return RET_NO_TARGET;
}
Ret tcp_client_create(TcpClient *thiz)
{
	if (thiz != NULL) {
		thiz->fd = socket(AF_INET, SOCK_STREAM, 0);
		if (thiz->fd < 0) {
			return RET_FAIL;
		}
		return RET_OK;
	}
	return RET_NO_TARGET;
}

Ret tcp_client_connect(TcpClient *thiz)
{
	int ret = -1;

	if (thiz != NULL && thiz->fd != -1) {
		ret = connect(thiz->fd, (void *)&thiz->addr, thiz->addr_len);
		if (ret == -1) {
			return RET_CONTINUE;
		}
		if (thiz->attr) {
			set_sock_opt(thiz->fd, thiz->attr);
		}
		return RET_OK;
	}

	return RET_NO_TARGET;
}

int tcp_client_read(TcpClient *thiz, int size)
{
	int ret;

	RwBuf *buf = thiz->buf;

	if (thiz != NULL && buf != NULL) {
		ret = read(thiz->fd, buf->mem + buf->wpos, size);	
		if (ret < 0) {
			if (errno == EAGAIN || errno == EWOULDBLOCK) {
				return -2;
			} else {
				thiz->status = DEAD;
				return -1;
			}
		}
	}
	
	return ret;
}
int tcp_client_wirte(TcpClient *thiz, int size)
{
	int ret = 0;
	RwBuf *buf = thiz->buf;

	if (thiz!= NULL && buf != NULL) {
		ret = write(thiz->fd, buf->mem + buf->rpos, size);	
		if (ret < 0) {
			if (errno == EAGAIN || errno == EWOULDBLOCK) {
				return -2;
			} else {
				thiz->status = DEAD;
				return -1;
			}
		}
	}
	
	return ret;
}

